package operators;

import java.util.List;
import java.util.Vector;

import org.jgap.Gene;
import org.jgap.Population;
import org.jgap.Chromosome;
import org.jgap.Configuration;
import org.jgap.InvalidConfigurationException;
import org.jgap.impl.MutationOperator;

@SuppressWarnings("serial")
public class MogaMutationOperator extends MutationOperator {

	/**
	 * Default constructor.
	 * 
	 * @param config Configuration :  Algorithm's configuration
	 * @param crossoverRate double : Mutation probability
	 * 
	 * @throws InvalidConfigurationException : Invalid configuration
	 */
	public MogaMutationOperator(Configuration config, double mutaProb) throws InvalidConfigurationException {
		// Intialize algorithm's configuration
		super(config, (int)(1/mutaProb));
	}
	
	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void operate(Population pop, List candidates) {
		
		// Prepare crossover
		candidates = new Vector(pop.size());	
		double mutaProb = 1/(double)this.getMutationRate();

		// Perform mutation (conserve size)
		for (int i = 0; i < pop.size(); i++) {
			
			Chromosome chromo = (Chromosome) pop.getChromosome(i);
			Gene[] genes = chromo.getGenes(); // Get genes
			
			boolean mutated = false;
			for (int j = 0; j < genes.length; j++) {
				
				// Mutate with a probability
				if (Math.random() < mutaProb) {
					Gene toMutate = genes[j];
					int geneSize = toMutate.size();
					double intensity = -1 + Math.random()*2;
					int index = (int) Math.floor(0 + Math.random()*geneSize);
					toMutate.applyMutation(index, intensity);
					mutated = true;
				}
			}
			
			// Add parents
			if (mutated) { // Clone if necessary
				chromo = (Chromosome) chromo.clone();
				chromo.getFitnessValue(); // Calculate
			}
			candidates.add(chromo);
		}
	}

}
